package com.gareve.twoSides.models;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.math.Vector2;
import com.gareve.twoSides.GameConstants;
import com.gareve.twoSides.input.InputStatus;

public class GameWorld {
	private static final String TAG = GameWorld.class.getSimpleName();
	
	private InputStatus inputStatus;

	//Game Objects
	public PlayerObject playerObjectA,playerObjectB;
	public ObstacleGenerator obstacleGenerator;
	public Collection<Obstacle> obstacles;
	
	//Game timers
	private float obstacleTimer;

	public GameWorld(){
		playerObjectA = new PlayerObject(GameConstants.SCREEN_WIDTH * 0.05f , GameConstants.SCREEN_HEIGHT * 0.5f);
		playerObjectB = new PlayerObject(GameConstants.SCREEN_WIDTH * 0.95f - PlayerObject.WIDTH , GameConstants.SCREEN_HEIGHT * 0.5f);
		
		obstacleGenerator = new ObstacleGenerator(GameConstants.SCREEN_WIDTH * 0.5f - ObstacleGenerator.WIDTH/2f, GameConstants.SCREEN_HEIGHT * 0.05f);
		
		obstacleTimer = GameConstants.OBSTACLE_GENERATION_PERIOD;		
		obstacles = new LinkedList<Obstacle>();
	}

	public void setInputStatus(InputStatus inputStatus) {
		this.inputStatus = inputStatus;
	}
	
	public boolean toTheLeft(Vector2 p){
		Vector2 ab =  obstacleGenerator.getPoint2().cpy().sub(obstacleGenerator.getPoint1());
		Vector2 ac =  p.cpy().sub(obstacleGenerator.getPoint1());
		
		float cross = ab.crs(ac);
		
		//Gdx.app.log(TAG, String.format("[%.2f,%.2f] [%.2f %.2f]@%.2f",ac.x,ac.y,ab.x,ab.y,cross));
		
		return cross > 0f;
	}
	
	public void processTap(Vector2 tap){
		if(toTheLeft(tap)){
			playerObjectA.setTarget(tap);
			//Gdx.app.log(TAG, "LEFT");
		}else{
			playerObjectB.setTarget(tap);
			//Gdx.app.log(TAG, "RIGHT");
		}
	}

	public void update(float delta) {
		//Obstacle Generation
		obstacleTimer -= delta;
		if(obstacleTimer <= 0f){
			obstacles.add(obstacleGenerator.generateObstacle());
			obstacleTimer += GameConstants.OBSTACLE_GENERATION_PERIOD;
		}

		playerObjectA.crashed = false;
		playerObjectB.crashed = false;
		//Obstacle Moving and collision
		for(Iterator<Obstacle> it = obstacles.iterator();it.hasNext();){
			Obstacle obstacle = it.next();
			obstacle.crashed = false;
			
			obstacle.move(delta);			
			if(obstacle.collide(playerObjectA)){
				obstacle.crashed = true;
				playerObjectA.crashed = true;
			}
			if(obstacle.collide(playerObjectB)){
				obstacle.crashed = true;
				playerObjectB.crashed = true;
			}

			if(obstacle.isAlive() == false)
				it.remove();
		}
		//Player update
		if(inputStatus.peek2(Keys.A) || inputStatus.peek2(Keys.Z)){
			playerObjectA.target = null;
			playerObjectA.move(getSpeed(inputStatus.peek2(Keys.A), inputStatus.peek2(Keys.Z), delta));
		}else if(playerObjectA.target != null){
			Vector2 direction = playerObjectA.target.cpy().sub(playerObjectA.getCenter()).nor().mul(delta);
			playerObjectA.move(direction);
		}
		
		if(inputStatus.peek2(Keys.UP) || inputStatus.peek2(Keys.DOWN)){
			playerObjectB.target = null;
			playerObjectB.move(getSpeed(inputStatus.peek2(Keys.UP), inputStatus.peek2(Keys.DOWN), delta));
		}else if(playerObjectB.target != null){
			Vector2 direction = playerObjectB.target.cpy().sub(playerObjectB.getCenter()).nor().mul(delta);
			playerObjectB.move(direction);
		}
	}
	
	private Vector2 getSpeed(boolean up,boolean down,float delta){
		Vector2 speed = new Vector2();
		if(up)speed.y = delta;
		if(down)speed.y = -delta;
		
		return speed;
	}
}
